package com.cloud.mall.conf.gateway;

import cn.hutool.json.JSONUtil;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.cloud.mall.enums.ExcEnum;
import com.cloud.mall.exp.CustomException;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

import java.net.URI;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @Author: 梁二东
 * @Date: 2024/12/5 14:26
 * @Description: 自定义默认的过滤器filter，配置文件
 * spring:
 *   cloud:
 *     gateway:
 *       # 默认过滤器全局生效
 *       default-filters:
 *         - Routing=gray
 **/
@Component
@Slf4j
public class GrayRoutingGatewayFilterFactory extends AbstractGatewayFilterFactory<GrayRoutingGatewayFilterFactory.Config> implements Ordered {

    @Autowired
    private DiscoveryClient discoveryClient;

    @Autowired
    private NacosDiscoveryProperties nacosDiscoveryProperties;

    public GrayRoutingGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            // 获取当前请求的服务 ID
            String serviceId = exchange.getRequest().getHeaders().getFirst("X-Service-ID");
            // 从请求头获取过滤条件
            String grayTag = exchange.getRequest().getHeaders().getFirst("X-Gray-Tag");
            // 如果头信息中没有 X-Gray-Tag 参数或参数值不等于config配置的值
            if (StringUtils.isBlank(grayTag) || !config.getTag().equals(grayTag)) {
                return chain.filter(exchange);
            }

            if (serviceId == null) {
//                exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);
//                return exchange.getResponse().setComplete();
                String path = exchange.getRequest().getURI().getPath();
                String method = Objects.requireNonNull(exchange.getRequest().getMethod()).name();
                throw CustomException.fail(ExcEnum.METHOD_NOT_ALLOWED.getCode(), "X-Service-ID不能为空", path, method);
            }
            // 根据服务id查询服务列表
            List<ServiceInstance> instances = discoveryClient.getInstances(serviceId);
            log.info("根据serviceId查询服务列表，serviceId={},instances={}", serviceId, JSONUtil.toJsonStr(instances));

            // 根据请求头条件过滤服务实例
            List<ServiceInstance> filteredInstances = instances.stream()
                    .filter(instance -> matchHeaderCondition(instance, grayTag))
                    .collect(Collectors.toList());

            // 如果没有匹配的实例，则使用默认的实例兜底
            List<ServiceInstance> routingInstances = filteredInstances.isEmpty() ? instances : filteredInstances;

            // 轮询或随机选择一个服务实例
            ServiceInstance instanceToRoute = getNextInstance(routingInstances);
            if (instanceToRoute != null) {
                // 构建新的 URI
                URI newUri = instanceToRoute.getUri().resolve(exchange.getRequest().getURI().getPath());
                // 修改请求的 URI
                exchange.getRequest().mutate().uri(newUri).build();
            }
            return chain.filter(exchange);
        };
    }

    private boolean matchHeaderCondition(ServiceInstance instance, String headerValue) {
        if (StringUtils.isBlank(headerValue)) {
            return true;
        }
        // 根据请求头匹配条件，可以自定义你的逻辑
        return instance.getMetadata().containsValue(headerValue); // 自定义匹配条件
    }

    private ServiceInstance getNextInstance(List<ServiceInstance> instances) {
        // 简易轮询逻辑，随机选择实例
        if (instances.isEmpty()) {
            return null; // 若没有实例，返回 null
        }
        // 简单随机实现
        int index = (int) (Math.random() * instances.size());
        return instances.get(index);
    }

    @Override
    public List<String> shortcutFieldOrder() {
        // 可以在此定义字段顺序
        return Arrays.asList("tag");
    }

    @Data
    public static class Config {
        // 可以在此定义任何配置属性
        private String tag;
    }

    @Override
    public int getOrder() {
        return LOWEST_PRECEDENCE;
    }
}
